package org.jetlinks.pro.auth;

import org.hswebframework.web.authorization.token.DefaultUserTokenManager;
import org.hswebframework.web.starter.jackson.CustomCodecsAutoConfiguration;
import org.hswebframework.web.system.authorization.defaults.configuration.AuthorizationServiceAutoConfiguration;
import org.jetlinks.pro.auth.sso.ThirdPartyProvider;
import org.jetlinks.pro.auth.sso.oauth2.CommonOAuth2SsoProvider;
import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

@Configuration
@ImportAutoConfiguration({
    AuthorizationServiceAutoConfiguration.class,
    CodecsAutoConfiguration.class,
    JacksonAutoConfiguration.class,
    CustomCodecsAutoConfiguration.class
})
public class AuthenticationTestConfiguration {

    @Bean
    public DefaultUserTokenManager userTokenManager() {
        return new DefaultUserTokenManager();
    }

    /**
     * 注册一个第三方登录支持类，模拟请求.
     */
    @Bean
    public List<ThirdPartyProvider> providers() {
        WebClient webClient = initWebClient();

        CommonOAuth2SsoProvider provider1 = new CommonOAuth2SsoProvider();
        provider1.setWebClient(webClient);
        provider1.setId("test-provider");
        provider1.setName("单元测试第三方支持");
        provider1.setClientId("test-clientId");
        provider1.setClientSecret("test-clientSecret");
        provider1.setAuthorizeUrl("https://test.com/oauth/authorize");
        provider1.setTokenUrl("https://test.com/oauth/token");
        provider1.setUserInfoUrl("https://test.com/user/info");
        provider1.setUserIdProperty("login");
        provider1.setRedirectUri("http://localhost:9000/jetlinks/sso/notify/test-provider");

        CommonOAuth2SsoProvider provider2 = new CommonOAuth2SsoProvider();
        provider2.setWebClient(webClient);
        provider2.setId("test-provider-2");
        provider2.setName("单元测试第三方支持");
        provider2.setClientId("test-clientId");
        provider2.setClientSecret("test-clientSecret");
        provider2.setAuthorizeUrl("https://test.com/oauth/authorize");
        provider2.setTokenUrl("https://test.com/oauth/token");
        provider2.setUserInfoUrl("https://test.com/user/info");
        provider2.setUserIdProperty("login");
        provider2.setRedirectUri("http://localhost:9000/jetlinks/sso/notify/test-provider");
        provider2.setTokenRequestType(null);

        return Arrays.asList(provider1, provider2);
    }

    /**
     * 模拟请求
     */
    private WebClient initWebClient() {
        WebClient webClient = Mockito.mock(WebClient.class);
        WebClient.RequestBodyUriSpec bodyUriSpec = Mockito.mock(WebClient.RequestBodyUriSpec.class);
        WebClient.RequestBodySpec bodySpec = Mockito.mock(WebClient.RequestBodySpec.class);
        WebClient.RequestHeadersSpec headersSpec = Mockito.mock(WebClient.RequestHeadersSpec.class);
        WebClient.RequestHeadersSpec headersSpec2 = Mockito.mock(WebClient.RequestHeadersSpec.class);
        WebClient.ResponseSpec spec = Mockito.mock(WebClient.ResponseSpec.class);
        WebClient.RequestHeadersUriSpec headersUriSpec = Mockito.mock(WebClient.RequestHeadersUriSpec.class);
        WebClient.ResponseSpec spec2 = Mockito.mock(WebClient.ResponseSpec.class);

        // requestToken
        Mockito.when(webClient.post())
            .thenReturn(bodyUriSpec);
        // requestToken: postbody
        Mockito.when(bodyUriSpec.uri(Mockito.anyString()))
            .thenReturn(bodySpec);
        Mockito.when(bodySpec.body(Mockito.any(BodyInserter.class)))
            .thenReturn(headersSpec);
        Mockito.when(headersSpec.accept(Mockito.any(MediaType.class)))
            .thenReturn(headersSpec);
        Mockito.when(headersSpec.retrieve())
            .thenReturn(spec);
        // requestToken: non postbody
        Mockito.when(bodyUriSpec.uri(Mockito.anyString(), Mockito.any(Function.class)))
            .thenReturn(bodySpec);
        Mockito.when(bodySpec.accept(Mockito.any(MediaType.class)))
            .thenReturn(bodySpec);
        Mockito.when(bodySpec.retrieve())
            .thenReturn(spec);

        Mockito.when(spec.bodyToMono(Mockito.any(Class.class)))
            .thenReturn(Mono.just("{\"access_token\":\"test-token\"}"));
        // getUserId
        Mockito.when(webClient.get())
            .thenReturn(headersUriSpec);
        Mockito.when(headersUriSpec.uri(Mockito.anyString(), Mockito.any(Function.class)))
            .thenReturn(headersSpec2);
        Mockito.when(headersSpec2.headers(Mockito.any(Consumer.class)))
            .thenReturn(headersSpec2);
        Mockito.when(headersSpec2.accept(Mockito.any(MediaType.class)))
            .thenReturn(headersSpec2);
        Mockito.when(headersSpec2.retrieve())
            .thenReturn(spec2);
        Mockito.when(spec2.bodyToMono(Mockito.any(Class.class)))
            .thenReturn(Mono.just("{\"login\":\"test\"}"));

        return webClient;
    }

}
